//
//  CLWebViewController.swift
//  clreader
//
//  Created by colin on 2019/7/28.
//  Copyright © 2019 colin. All rights reserved.
//

import UIKit
import WebKit

class CLWebViewController: UIViewController {

    private var contentWebView:WKWebView?
    private lazy var titleItem = UINavigationItem(title: "")
    private lazy var progessView = UIProgressView(progressViewStyle: .default)
    
    private var urlString = ""
    
    //MARK:init
    @objc convenience init(urlString:String?) {
        self.init()
        if let urlString_ = urlString {
            self.urlString = urlString_
        }
    }
    
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    //MARK:life cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.white
        
        //navigationbar
        let topBar = UINavigationBar(frame: CGRect.zero)
        topBar.barTintColor = UIColor.white
        topBar.tintColor = UIColor(hex: "00a1ff")
        topBar.titleTextAttributes = [NSAttributedString.Key.font:UIFont.systemFont(ofSize: 17.0),NSAttributedString.Key.foregroundColor:UIColor(hex:"404040")]
        
        let backItem = UIBarButtonItem(image: UIImage(named:"button_navigation_back")?.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(self.back(sender:)))
        let closeItem = UIBarButtonItem(image: UIImage(named:"button_navigation_close")?.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(self.actionClose(sender:)))
        self.titleItem.leftBarButtonItems = [backItem, closeItem]
        
        let refreshItem = UIBarButtonItem(image: UIImage(named:"button_navigation_refrfesh")?.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(self.refresh(sender:)))
        self.titleItem.rightBarButtonItems = [refreshItem]
        
        topBar.items = [self.titleItem]
        
        self.view.addSubview(topBar)
        topBar.snp.makeConstraints { (make) in
            make.left.right.equalTo(topBar.superview!)
            if #available(iOS 11.0, *) {
                make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top)
                make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.top).offset(44.0)
            } else {
                make.top.equalToSuperview()
                make.height.equalTo(64.0)
            }
        }
        
        //进度条
        self.view.addSubview(self.progessView)
        self.progessView.progress = 0
        self.progessView.isHidden = true
        self.progessView.progressTintColor = UIColor(hex: "00acff")
        self.progessView.snp.makeConstraints { (make) in
            make.left.right.equalTo(self.progessView.superview!)
            make.top.equalTo(topBar.snp.bottom)
            make.height.equalTo(1.0)
        }
        
        let configuretion = WKWebViewConfiguration()
        // Webview的偏好设置
        configuretion.preferences = WKPreferences()
        configuretion.preferences.minimumFontSize = 10
        configuretion.preferences.javaScriptEnabled = true
        // 默认是不能通过JS自动打开窗口的，必须通过用户交互才能打开
        configuretion.preferences.javaScriptCanOpenWindowsAutomatically = false
        
        // 通过js与webview内容交互配置
        configuretion.userContentController = WKUserContentController()
        
        self.contentWebView = WKWebView(frame: CGRect.zero, configuration: configuretion)
        self.contentWebView?.scrollView.contentInset = UIEdgeInsets.zero
        self.contentWebView?.allowsBackForwardNavigationGestures = true
        self.contentWebView?.navigationDelegate = self
        self.contentWebView?.uiDelegate = self
        
        self.view.insertSubview(self.contentWebView!, at: 0)
        self.contentWebView?.snp.makeConstraints { (make) in
            make.left.right.equalTo(self.view)
            make.top.equalTo(topBar.snp.bottom)
            if #available(iOS 11.0, *) {
                make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom)
            } else {
                make.bottom.equalToSuperview()
            }
        }
        
        //添加观察者
        self.contentWebView?.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
        self.contentWebView?.addObserver(self, forKeyPath: "title", options: .new, context: nil)
        
        if let url = URL(string: self.urlString) {
            let urlRequest = URLRequest(url: url)
            _ = self.contentWebView?.load(urlRequest)
        }
        
    }
    
    //MARK:观察者
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        if let keyPath_ = keyPath,let webView = self.contentWebView {
            if keyPath_ == "estimatedProgress" {
                if webView.estimatedProgress == 1 {
                    self.progessView.isHidden = true
                    self.progessView.setProgress(Float(webView.estimatedProgress), animated: false)
                }
                else {
                    self.progessView.isHidden = false
                    self.progessView.setProgress(Float(webView.estimatedProgress), animated: true)
                }
            }
            
            if keyPath_ == "title" {
                self.titleItem.title = webView.title
            }
        }
    }
    
    //deinit
    deinit {
        self.contentWebView?.removeObserver(self, forKeyPath: "estimatedProgress")
        self.contentWebView?.removeObserver(self, forKeyPath: "title")
    }
    
    //MARK:返回
    @objc private func back(sender:Any) {
        if let canGoBack = self.contentWebView?.canGoBack , canGoBack {
            _ = self.contentWebView?.goBack()
        }
        else {
            _ = self.navigationController?.popViewController(animated: true)
        }
    }
    
    //MARK:返回
    @objc private func actionClose(sender:Any) {
        _ = self.navigationController?.popViewController(animated: true)
    }
    
    //MARK:刷新
    @objc private func refresh(sender:Any) {
        if let isLoading = self.contentWebView?.isLoading , isLoading {
            self.contentWebView?.stopLoading()
        }
        _ = self.contentWebView?.reload()
    }
    
}

extension CLWebViewController : WKNavigationDelegate {
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        decisionHandler(.allow)
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    }
}

extension CLWebViewController:WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        
        let scriptName = message.name
        let messageData = message.body as? [String:Any]
        
    }
}

extension CLWebViewController:WKUIDelegate {
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        let alertController = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
        let confirmAction = UIAlertAction(title: "确定", style: .default, handler:{ (action) in
            completionHandler()
        }
        )
        alertController.addAction(confirmAction)
        self.present(alertController, animated: true, completion: nil)
    }
    
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        let alertController = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
        let cancleAction = UIAlertAction(title: "取消", style: .default, handler:{ (action) in
            completionHandler(false)
        }
        )
        let confirmAction = UIAlertAction(title: "确定", style: .default, handler:{ (action) in
            completionHandler(true)
        }
        )
        alertController.addAction(cancleAction)
        alertController.addAction(confirmAction)
        self.present(alertController, animated: true, completion: nil)
    }
    
    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        let alertController = UIAlertController(title: prompt, message: "", preferredStyle: .alert)
        alertController.addTextField { (textFiled) in
            textFiled.text = defaultText
        }
        let confirmAction = UIAlertAction(title: "完成", style: .default, handler:{ (action) in
            if let textFileds = alertController.textFields,!textFileds.isEmpty,let text = textFileds[0].text {
                completionHandler(text)
            }
            else {
                completionHandler("")
            }
        }
        )
        alertController.addAction(confirmAction)
        self.present(alertController, animated: true, completion: nil)
    }
    
}

private extension WKWebView {
    func evaluateJavaScript(methodName:String,parameter:JSONObject?) {
        do {
            var parameterString:String?
            if let parameter_ = parameter , !parameter_.isEmpty {
                let jsonData = try JSONSerialization.data(withJSONObject: parameter_, options: .prettyPrinted)
                parameterString = jsonData.base64EncodedString(options: .endLineWithLineFeed)
            }
            
            var js = ""
            if let parameterString_ = parameterString , !parameterString_.isEmpty {
                js = "\(methodName)('" + parameterString_ + "')"
            }
            else {
                js = "\(methodName)()"
            }
            
            js = js.replacingOccurrences(of: "\\", with: "")
            
            self.evaluateJavaScript(js, completionHandler: { (callBack, error) in
                if let callBack_ = callBack {
                    print("js回调----- \(methodName) ----- \(callBack_)")
                }
                
                if let error_ = error {
                    print("js调用异常 ----- \(methodName) ----- \(error_)")
                }
                
            })
        }
        catch {
            print("参数序列化错误----- \(methodName) -----")
        }
    }
}
